import re
import allure
from jsonpath import jsonpath

from src.log import log
from src.db import MysqlUtil
from src.config_util import Config
from src.common import write_extract, is_digit


class Extract(object):
    def __init__(self, response, expressions):
        self.response = response
        self.expressions = expressions
        self.env_info = Config("conf/env.yml").get_conf(Config().get_conf("env"))

    def extract(self):
        for item in self.expressions:
            key = list(item.keys())[0]
            expression = item.get(key)
            try:
                # 正则表达式提取变量
                if expression.startswith("${/") and expression.endswith("/}"):
                    self.extract_by_regex(key, expression[3: -2].strip())
                # 模版语法提取值
                elif expression.startswith("${") and expression.endswith("}"):
                    # sql取值
                    if "select" in expression.lower() and "from" in expression.lower():
                        self.extract_by_sql(key, expression[2: -1].strip())
                # jsonpath提取值
                elif "$." in expression.lower():
                    self.extract_by_jsonpath(key, expression)
                # response对象取值
            except Exception as e:
                with allure.step(f"后置保存变量: {key}, 保存结果: {e}"):
                    log.error(f"后置保存变量: {key}, 保存结果: {e}")
                raise Exception(e)

    def extract_by_jsonpath(self, key, extract):
        try:
            extract_value = jsonpath(self.response.json(), extract)[0]
            write_extract(key, extract_value)
            with allure.step(f"后置保存变量: {key}, 保存结果: {extract_value}"):
                log.info(f"后置保存变量: {key}, 保存结果: {extract_value}")
        except TypeError:
            raise Exception(f"jsonpath表达式错误或非预期响应内容。表达式: {extract};响应内容: {self.response.json()}")

    def extract_by_sql(self, key, expression):
        try:
            mysql = MysqlUtil(**self.env_info.get("mysql"))
            result = list(mysql.query_sql(expression).values())[0]
            write_extract(key, result)
            with allure.step(f"后置保存变量: {key}, 保存结果: {result}"):
                log.info(f"后置保存变量: {key}, 保存结果: {result}")
        except Exception:
            raise Exception(f"sql语句错误或执行异常。sql语句: {expression}")

    def extract_by_regex(self, key, reg_expression):
        try:
            result = re.search(reg_expression, self.response.text, flags=re.S).group()
            if is_digit(result):
                write_extract(key, eval(result))
            else:
                write_extract(key, result)
            with allure.step(f"后置保存变量: {key}, 保存结果: {result}"):
                log.info(f"后置保存变量: {key}, 保存结果: {result}")
        except Exception:
            raise Exception(f"正则表达式或非预期响应内容。表达式: {reg_expression}; 响应内容: {self.response.text}")
